using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;

namespace Avanade.PolicyInjection
{
    /// <summary>
    /// A configuration element class that stores the config data for
    /// the <see cref="WcfValidationCallHandler"/>.
    /// </summary>
    [Assembler(typeof(WcfValidationCallHandlerAssembler))]
    public class WcfValidationCallHandlerData : CallHandlerData
    {
        private const string RuleSetPropertyName = "ruleSet";
        private const string SpecificationSourcePropertyName = "specificationSource";

        /// <summary>
        /// Create a new <see cref="WcfValidationCallHandlerData"/> instance.
        /// </summary>
        public WcfValidationCallHandlerData()
            : base()
        {
        }

        /// <summary>
        /// Create a new <see cref="WcfValidationCallHandlerData"/> instance.
        /// </summary>
        /// <param name="handlerName">Name of handler in configuration.</param>
        public WcfValidationCallHandlerData(string handlerName)
            : base(handlerName, typeof(WcfValidationCallHandler))
        {
        }

        /// <summary>
        /// The ruleset name to use for all types. Empty string means default ruleset 
        /// </summary>
        /// <value>The "ruleSet" configuration property.</value>
        [ConfigurationProperty(RuleSetPropertyName)]
        public string RuleSet
        {
            get { return (string)base[RuleSetPropertyName]; }
            set { base[RuleSetPropertyName] = value; }
        }

        /// <summary>
        /// SpecificationSource (Both | Attributes | Configuration) : Where to look for validation rules. Default is Both.
        /// </summary>
        /// <value>The "specificationSource" configuration attribute.</value>
        [ConfigurationProperty(SpecificationSourcePropertyName, IsRequired = true, DefaultValue = Avanade.PolicyInjection.SpecificationSource.Both)]
        public Avanade.PolicyInjection.SpecificationSource SpecificationSource
        {
            get { return (Avanade.PolicyInjection.SpecificationSource)base[SpecificationSourcePropertyName]; }
            set { base[SpecificationSourcePropertyName] = value; }
        }
    }

    /// <summary>
    /// A class use 
    /// </summary>
    public class WcfValidationCallHandlerAssembler : IAssembler<ICallHandler, CallHandlerData>
    {
        /// <summary>
        /// Builds an instance of the subtype of <typeparamref name="TObject"/> type the receiver knows how to build,  based on 
        /// an a configuration object.
        /// </summary>
        /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
        /// <param name="objectConfiguration">The configuration object that describes the object to build.</param>
        /// <param name="configurationSource">The source for configuration objects.</param>
        /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
        /// <returns>A fully initialized instance of the <typeparamref name="TObject"/> subtype.</returns>
        public ICallHandler Assemble(IBuilderContext context, CallHandlerData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
        {
            WcfValidationCallHandlerData castedHandlerData = (WcfValidationCallHandlerData)objectConfiguration;

            WcfValidationCallHandler callHandler = new WcfValidationCallHandler(castedHandlerData.RuleSet, castedHandlerData.SpecificationSource);

            return callHandler;
        }
    }
}
